5. 数据访问 - EntityFramework集成
前言
Masa
提供了基于EntityFramework
的数据集成,并提供了数据过滤与软删除的功能,下面我们将介绍如何使用它?
MasaDbContext入门
- 安装.Net 6.0
新建ASP.NET Core 空项目
Assignment.MasaEntityFramework
,并安装Masa.Contrib.Data.EntityFrameworkCore
、Swashbuckle.AspNetCore
、Microsoft.EntityFrameworkCore.InMemory
、Microsoft.EntityFrameworkCore.Tools
1
2
3
4dotnet add package Masa.Contrib.Data.EntityFrameworkCore --version 0.4.0-rc.4
dotnet add package Swashbuckle.AspNetCore --version 6.2.3
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0.5
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 6.0.5安装
Swashbuckle.AspNetCore
是为了方便通过Swagger
来操作服务
安装Microsoft.EntityFrameworkCore.InMemory
是为了方便,因此使用内存数据库,如果需要使用其他数据库,请自行安装对应的包
安装Microsoft.EntityFrameworkCore.Tools
是为了使用CodeFirst创建数据库新建类
User
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class User
{
public int Id { get; set; }
public string Name { get; set; }
public uint Gender { get; set; }
public DateTime BirthDay { get; set; }
public DateTime CreationTime { get; set; }
public User()
{
this.CreationTime = DateTime.Now;
}
}新建用户上下文
UserDbContext.cs
1
2
3
4
5
6
7
8public class UserDbContext : MasaDbContext
{
public DbSet<User> User { get; set; }
public UserDbContext(MasaDbContextOptions options) : base(options)
{
}
}UserDbContext
改为继承MasaDbContext
, 并新增一个参数的构造函数,参数类型为MasaDbContextOptions
当项目中存在多个DbContext时,需要改为继承MasaDbContext<TDbContext>
,构造函数参数类型改为MasaDbContext<TDbContext>
新建类
AddUserRequest
作为添加用户的参数1
2
3
4
5
6
7
8public class AddUserRequest
{
public string Name { get; set; }
public uint Gender { get; set; }
public DateTime BirthDay { get; set; }
}新建类
HostExtensions
用于迁移数据库(使用CodeFirst)1
2
3
4
5
6
7
8
9
10
11
12
13
14public static class HostExtensions
{
public static void MigrateDbContext<TContext>(
this IHost host, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<TContext>();
context.Database.EnsureCreated();
seeder(context, services);
}
}
}修改
Program.cs
,新增Swagger
支持1
2
3
4
5
6
7builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
不需要
Swagger
可不添加,使用Swagger仅仅是为了测试调用服务,使用Postman
或其他的Http工具也可以
修改
Program.cs
,添加用户上下文(重点)1
2
3
4builder.Services.AddMasaDbContext<UserDbContext>(options =>
{
options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test")
});修改
Program.cs
,使项目支持CodeFirst1
2
3app.MigrateDbContext<UserDbContext>((context, services) =>
{
});不需要CodeFirst,不支持代码生成数据库可不添加
测试
MasaDbContext
,修改Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15app.MapPost("/add", (UserDbContext dbContext, [FromBody] AddUserRequest request) =>
{
dbContext.Set<User>().Add(new User()
{
Name = request.Name,
Gender = request.Gender,
BirthDay = request.BirthDay
});
dbContext.SaveChanges();
});
app.MapGet("/list", (UserDbContext dbContext) =>
{
return dbContext.Set<User>().ToList();
});自行运行项目,执行
add
后创建一个新的用户,之后执行list
得到一个以上的用户数据,则证明MasaDbContext
使用无误
如何使用软删除
选中
Assignment.MasaEntityFramework
并安装Masa.Contrib.Data.Contracts.EF
1
dotnet add package Masa.Contrib.Data.Contracts.EF --version 0.4.0-rc.4
修改类
User
,并实现ISoftDelete
,代码改为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class User : ISoftDelete//重点:改为实现ISoftDelete
{
public int Id { get; set; }
public string Name { get; set; }
public uint Gender { get; set; }
public DateTime BirthDay { get; set; }
public DateTime CreationTime { get; set; }
public bool IsDeleted { get; private set; }
public User()
{
this.CreationTime = DateTime.Now;
}
}增加实现
ISoftDelete
,并为IsDeleted
属性添加set支持(可以是private set;)修改
Program.cs
,并启用数据过滤1
2
3
4
5builder.Services.AddMasaDbContext<UserDbContext>(options =>
{
options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test");
options.UseFilter();//启用数据过滤,完整写法:options.UseFilter(filterOptions => filterOptions.EnableSoftDelete = true);
});测试软删除是否成功
修改
Program.cs
,新增删除方法1
2
3
4
5
6app.MapDelete("/delete", (UserDbContext dbContext, int id) =>
{
var user = dbContext.Set<User>().First(u => u.Id == id);
dbContext.Set<User>().Remove(user);
dbContext.SaveChanges();
});
最后,先调用add
方法创建用户后,之后再调用list
方法获取所有的用户列表,并取出任意一条id信息,然后再调用delete
方法删除用户,最后再调用list
方法,查看取出的id是否存在,以此来验证软删除是否有效。
如何临时禁用软删除过滤
默认查询中会将标记已经被删除的数据过滤不再进行查询,但也有一些场景需要查询所有的数据,此时就需要用到数据过滤IDataFilter
新增
All
方法用于查询所有的数据(包含标记已经删除的数据)1
2
3
4
5
6
7
8app.MapGet("/all", (UserDbContext dbContext, [FromServices] IDataFilter dataFilter) =>
{
//通过DI获取到IDataFilter,并调用其Disable方法可临时禁用ISoftDelete条件过滤
using (dataFilter.Disable<ISoftDelete>())
{
return dbContext.Set<User>().ToList();
}
});重新运行项目,重复执行验证软删除步骤,确保通过
list
方法访问不到数据重复运行验证软删除步骤的原因在于本示例使用的是内存数据库,项目停止后,所有数据都会被清空,重新执行是为了确保数据存在,仅被标记为删除
执行
all
方法,获取所有的数据,查看id所对应的用户数据是否存在
从配置文件中获取数据库连接字符串
选中项目
Assignment.MasaEntityFramework
,并安装Masa.Contrib.Data.EntityFrameworkCore.InMemory
1
dotnet add package Masa.Contrib.Data.EntityFrameworkCore.InMemory --version 0.4.0-rc.4
根据需要安装对应数据库包即可,如:
Masa.Contrib.Data.EntityFrameworkCore.SqlServer
(SqlServer)、Masa.Contrib.Data.EntityFrameworkCore.Pomelo.MySql
(Pomelo提供的MySql)、Masa.Contrib.Data.EntityFrameworkCore.Oracle
(Oracle)等修改
Program.cs
,调整添加用户上下文配置为:1
builder.Services.AddMasaDbContext<UserDbContext>(options => options.UseInMemoryDatabase().UseFilter());
修改
appsettings.json
,增加用户数据库连接字符串:1
2
3
4
5{
"ConnectionStrings": {
"DefaultConnection": "test"//更换为指定的数据库连接字符串
}
}修改
Program.cs
,新增database
方法,验证当前数据库是test
1
2
3
4
5
6
7
8
9
10
11
12
13
14app.MapGet("/database", (UserDbContext dbContext) =>
{
var field = typeof(MasaDbContext).GetField("Options", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)!;
var masaDbContextOptions = field.GetValue(dbContext) as MasaDbContextOptions;
foreach (var dbContextOptionsExtension in masaDbContextOptions!.Extensions)
{
if (dbContextOptionsExtension is InMemoryOptionsExtension memoryOptionsExtension)
{
return memoryOptionsExtension.StoreName;
}
}
return "";
});
最后访问http://localhost:5002/database
,验证当前的数据库名称与修改后的数据库名称是否一致
常见问题
- 如何更改默认读取的配置节点?
修改用户上下文
UserDbContext
并增加ConnectionStringName
特性:1
2
3
4
5
6
7
8
9[//自定义节点名 ]
public class UserDbContext : MasaDbContext
{
public DbSet<User> User { get; set; }
public UserDbContext(MasaDbContextOptions options) : base(options)
{
}
}修改配置
appsettings.json
1
2
3
4
5{
"ConnectionStrings": {
"User": "test"//改为从User节点读取数据库连接字符串
}
}
- 除了从配置文件中获取,还支持从其他地方获取数据库连接字符串吗?
目前有两种办法可以更改数据库连接字符串。
方法1: 修改Program.cs
,并删除appsettings.json
数据库连接字符串的配置
修改
Program.cs
1
2
3
4
5
6
7builder.Services.Configure<MasaDbConnectionOptions>(option =>
{
option.ConnectionStrings = new ConnectionStrings(new List<KeyValuePair<string, string>>()
{
new("User", "test2")//其中键为节点名,与ConnectionStringName特性的Name值保持一致即可,如果未指定ConnectionStringName,则应该为DefaultConnection,值为数据库连接字符串
});
});修改
appsettings.json
配置1
2
3// "ConnectionStrings": {
// "User": "test"
// },调用
database
方法,验证当前数据库是否为test2
方法2: 重写IConnectionStringProvider
和IDbConnectionStringProvider
的实现并添加到DI中
新建类
CustomizeConnectionStringProvider
1
2
3
4
5
6public class CustomizeConnectionStringProvider : IConnectionStringProvider
{
public Task<string> GetConnectionStringAsync(string name = "DefaultConnection") => Task.FromResult (GetConnectionString(name));
public string GetConnectionString(string name = "DefaultConnection") => "test3";
}新建类
CustomizeDbConnectionStringProvider
1
2
3
4
5
6
7public class CustomizeDbConnectionStringProvider : IDbConnectionStringProvider
{
public List<MasaDbContextConfigurationOptions> DbContextOptionsList { get; } = new()
{
new MasaDbContextConfigurationOptions("test3")
};
}修改
Program.cs
1
2builder.Services.AddSingleton<IConnectionStringProvider,CustomizeConnectionStringProvider>();
builder.Services.AddSingleton<IDbConnectionStringProvider,CustomizeDbConnectionStringProvider>();调用
database
方法,验证当前数据库是否为test3
总结
本篇文章主要讲解了MasaDbContext
的基本用法以及软删除、数据过滤如何使用,下篇文章我们会讲解一下MasaDbContext
是如何实现软删除、数据过滤的,以及本篇文章中提到使用数据库时不指定数据库链接字符串时如何实现的
本章源码
Assignment05
https://github.com/zhenlei520/MasaFramework.Practice
开源地址
MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks
MASA.Contrib:https://github.com/masastack/MASA.Contrib
MASA.Utils:https://github.com/masastack/MASA.Utils
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
5. 数据访问 - EntityFramework集成
https://blogs.masastack.com/2022/05/29/masa/framework/practice/5. 数据访问 - EntityFramework集成/